/*************************************************************************
    > File Name: smsh1.c
    > Author: Xing.Dai
    > Mail: Xing.Dai@aliyun.com 
    > Created Time: 2017-05-26 23:15
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>

#define DFL_PROMPT ">"
#define YES		1
#define NO		0

#define is_delim(x) ((x) == ' ' || (x) == '\t')

/**
 * @Synopsis  initialize shell.
 */
void setup()
{
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
}


void fatal(char *s1, char *s2, int n)
{
	fprintf(stderr, "Error: %s, %s\n", s1, s2);
	exit(n);
}


/**
 * @Synopsis  Run a program pass it arguments.
 *
 * @Param argv
 *
 * @Returns   status returned via wait, or -1 on error.
 */
int execute(char **argv)
{
	int pid;
	int child_info = -1;

	if(argv[0] == NULL){	/* Nothing succeeds. */
		return 0;
	}

	if((pid = fork()) == 0){
		signal(SIGINT, SIG_DFL);
		signal(SIGQUIT, SIG_DFL);
		
		execvp(argv[0], argv);

		perror("Can not execute command");
		exit(1);

	} else {
		if(wait(&child_info) == -1){
			perror("wait");
		}
	}

	return child_info;
}

void *emalloc(size_t n)
{
	void *rv;

	if((rv = malloc(n)) == NULL)
		fatal("out of memory", "", 1);

	return rv;
}

void *erealloc(void *p, size_t n)
{
	void *rv;
	if((rv = realloc(p, n)) == NULL)
		fatal("realloc() failed", "", 1);

	return rv;
}

void freelist(char **list)
{
	char **cp = list;
	while(*cp)
		free(*cp++);
	free(list);
}

char * newstr(char *s, int l)
{
	char *rv = emalloc(l + 1);

	rv[1] = '\0';
	strncpy(rv, s, l);

	return rv;
}

char **splitline(char *line)
{
	char **args;
	int spots = 0;	/* spots in table */
	int bufspace = 0;
	int argnum = 0;
	char *cp = line;
	char *start;
	int len;

	if(line == NULL)	/* Handle special case. */
		return NULL;

	args = emalloc(BUFSIZ);
	bufspace = BUFSIZ;
	spots = BUFSIZ / sizeof(char *);

	while(*cp != '\0'){
		while(is_delim(*cp))
			cp++;	/* Skip leading spaces. */

		if(*cp == '\0')	/* Quit at end-of-string. */
			break;

		/* Make sure the array has room(+1 for NULL)*/ 
		if(argnum + 1 >= spots){
			args = erealloc(args, bufspace + BUFSIZ);
			bufspace += BUFSIZ;
			spots += (BUFSIZ / sizeof(char *));
		}

		/* Mark start, then find end of word. */
		start = cp;
		len = 1;
		while(*++cp != '\0' && !(is_delim(*cp)))
			len++;
		args[argnum++] = newstr(start, len);

	}
	args[argnum] = NULL;
	return args;
}

/**
 * @Synopsis  Read next command line from fp
 *
 * @Param prompt
 * @Param fp
 *
 * @Returns   
 */
char *next_cmd(char *prompt, FILE *fp)
{	
	char *buf;
	int bufspace = 0;
	int pos = 0;
	int c;

	printf("%s ", prompt);

	while((c = getc(fp)) != EOF){
		if(pos + 1 >= bufspace){
			if(bufspace == 0)
				buf = emalloc(BUFSIZ);
			else
				buf = erealloc(buf, bufspace + BUFSIZ);
			bufspace += BUFSIZ;
		}

		if(c == '\n')
			break;

		buf[pos++] = c;
	}

	if(c == EOF && pos == 0)
		return NULL;
	buf[pos] = '\0';
	return buf;
}

int main()
{
	char *cmdline, *prompt, **arglist;
	int result;

	prompt = DFL_PROMPT;
	setup();

	while((cmdline = next_cmd(prompt, stdin)) != NULL){
		if((arglist = splitline(cmdline)) != NULL){
			result = execute(arglist);
			result = result;
			freelist(arglist);
		}
		free(cmdline);
	}
	return 0;
}


